package com.tbit.uqbike.service.business.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.tbit.uqbike.constant.OperaPswConstant;
import com.tbit.uqbike.enums.SystemCodeEnum;
import com.tbit.uqbike.manager.exception.BaseException;
import com.tbit.uqbike.object.pojo.*;
import com.tbit.uqbike.object.pojo.dto.OtaUpdateDTO;
import com.tbit.uqbike.object.pojo.vo.OtaVO;
import com.tbit.uqbike.object.view.JsonResult;
import com.tbit.common.entity.view.Result;
import com.tbit.uqbike.service.business.TaskService;
import com.tbit.uqbike.webmanager.dao.core.AccountDao;
import com.tbit.uqbike.webmanager.dao.core.MachineDao;
import com.tbit.uqbike.webmanager.dao.core.OtaAccessConfigDao;
import com.tbit.uqbike.webmanager.dao.core.TaskDao;
import com.tbit.uqbike.webmanager.util.DateUtils;
import com.tbit.uqbike.webmanager.util.FileLoadUtils;
import com.tbit.uqbike.webmanager.util.StringUtils;
import com.tbit.uqbike.webmanager.util.excel.ExcelUtil;
import com.tbit.uqbike.webmanager.util.http.HttpRequestUtils;
import com.tbit.uqbike.webmanager.util.sign.Md5Utils;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.NameValuePair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @program: uqbike-manager-new
 * @description:
 * @author: Jing
 * @create: 2021-05-24 16:25
 **/
@RefreshScope
@Service
@Slf4j
public class TaskServiceImpl implements TaskService {


    @Autowired
    private TaskDao taskDao;
    @Autowired
    private MachineDao machineDao;
    @Autowired
    private OtaAccessConfigDao accessConfigDao;
    @Autowired
    private AccountDao accountDao;
    @Value("${ota.ip}")
    private  String url;

    @Value("${ota.appkey}")
    private String superAppkey;

    @Value("${ota.appSecret}")
    private String superAppSecret;


    public static void main(String[] args) {
        Map<String, String> head = new HashMap<>();
        long ts = System.currentTimeMillis();
//        String appkey = OperaPswConstant.OTA_KEY;
//        String appSecret = OperaPswConstant.OAT_SECRET;
        String appkey = "E7B0171363F74EFF9F4BF2ACD388753D";
        String appSecret = "BCD64C5CD0FDC2082923075FF7C4D657";
        head.put("appkey", appkey);
        head.put("sign", Md5Utils.hash(String.format("%s.%d.%s.%d.%s", appkey, ts, appSecret, ts, appkey)));
        head.put("ts", String.valueOf(ts));
        System.out.println(head);
    }

    @Override
    public Map<String, Object> getInfo(Integer taskId, Integer accountId) {
        log.info("url:"+url);
        return send(url + "/otaman/tertask/updateMsg/" + taskId, null, 2, accountId);
    }

    @Override
    public Map<String, Object> selectTaskUser(Task task,int pageNum,int pageSize) {
        if (Objects.isNull(task.getAccountId())){
            throw new BaseException("请选择区域");
        }
        /*查询出该区域下的taskId*/
        List<Integer> taskIds = taskDao.selectByAccountId(task.getAccountId());
        log.info("{}-下的taskId{}", task.getAccountId(), taskIds);
        if (CollectionUtil.isEmpty(taskIds)){
            return new HashMap<>();
        }
        task.setTaskIds(taskIds);
        log.info("url:"+url);
        return send(url + "/otaman/tertask/tlist?pageNum="+pageNum+"&pageSize="+pageSize, task, 1, task.getAccountId());
    }

    @Override
    public Result<Object> add(Task task) {
        //语音大小判断
        if (!FileLoadUtils.checkFileSize(task.getFile(), 200, "K")) {
            throw new BaseException("语音文件大小不能超过200Kb,请处理后重新上传。");
        }
        List<String> mons = StringUtils.str2List(task.getTerMnos(), ",", Boolean.TRUE, Boolean.TRUE);
        //上级上限为5000台设备
        if (mons.size() > 5000) {
            throw new BaseException(SystemCodeEnum.REACH_THE_LIMIT);
        }

        //共享系统不存在的设备
        List<OtaExport> otaExportList = new ArrayList<>();
        List<String> noInMachineNos = checkMnos(mons, task.getAccountId());
        if (CollectionUtil.isNotEmpty(noInMachineNos)){
            noInMachineNos.forEach(mon -> {
                otaExportList.add(new OtaExport(mon, "系统不存在"));
                mons.remove(mon);
            });
        }

        //判断是否是自定义输入id
        if(!task.getModule().contains("DEVICE_RES") ){
            task.setModule("DEVICE_RES"+task.getModule());
        }

        //校验是否在ota系统
        OtaUpdateDTO otaUpdateDTO = new OtaUpdateDTO();
        otaUpdateDTO.setAppKey(superAppkey);
        otaUpdateDTO.setTerMnos(task.getTerMnos());
        Object objectJson = JSONObject.toJSON(otaUpdateDTO);
        log.info("url:"+url);
        Map<String, Object> existMachineResultMap = OTAsend(url + "/otaman/tertask/getExistMachine", objectJson, 1, accountDao.getBrandIdByAccountIdV2(task.getAccountId()));

        //获取ota设备信息
        List<String> data = (List<String>) existMachineResultMap.get("data");
        if (CollectionUtil.isNotEmpty(data) && CollectionUtil.isNotEmpty(mons)) {
            for (String datum : data) {
                if (mons.contains(datum)){
                    continue;
                }
                otaExportList.add(new OtaExport(datum, "OTA不存在"));
                mons.remove(datum);
            }
        }

       checkOnline(mons, otaExportList);

        if (CollectionUtil.isNotEmpty(otaExportList)){
            OtaVO otaVO = new OtaVO();
            otaVO.setOtaExportList(otaExportList);
            //导出excel
            ExcelUtil<OtaExport> excelUtil = new ExcelUtil<>(OtaExport.class);
            otaVO.setFileName(excelUtil.exportExcel(otaExportList, "失败设备编号").getData());
            return Result.error(otaVO);
        }
        //异步处理
        if (StringUtils.isNotEmpty(mons)) {
            extracted(task);
        }
        return Result.success();
    }

    //校验是否在线
    private void checkOnline(List<String> mons, List<OtaExport> otaExportList) {
        if (CollectionUtil.isEmpty(mons)){
            return;
        }
        Map<String, MachineStatus> onlineMap = machineDao.selectOnlineMachine(mons);
        Iterator<String> iterator = mons.iterator();
        while (iterator.hasNext()) {
            String mon = iterator.next();
            if (Objects.isNull(onlineMap.get(mon)) || DateUtil.between(onlineMap.get(mon).getBatDt(), new Date(), DateUnit.MINUTE) > 5) {
                otaExportList.add(new OtaExport(mon, "设备不在线"));
                iterator.remove(); // 使用迭代器的 remove 方法
            }
        }
    }

    @Async
    public void extracted(Task task) {
        Object obj = send(url + "/otaman/tertask/addVoiceTask", task, 0, task.getAccountId());
        log.info("ota返回结果:{}",JSON.toJSONString(obj));
        if (StringUtils.isNotNull(obj)) {
            Map<String, Object> map = (Map<String, Object>) obj;
            task = new Task((Integer) map.get("taskId"), task.getAccountId(), new Date(task.getATime()), DateUtils.getNowDate());
            taskDao.add(task);
        }
    }

    @Override
    public int edit(Task task) {
        log.info("url:"+url);
        return StringUtils.isNull(send(url + "/otaman/tertask/update", task, 1, task.getAccountId())) ? 0 : 1;
    }

    @Override
    public Map<String, Object> selectTerMno(Task task) {
        log.info("url:"+url);
        return send(url + "/otaman/tertask/updateMsg/terMno", task, 1, task.getAccountId());
    }

    @Override
    public List<String> checkMnos(List<String> mons, Integer accountId) {
        List<Machine> machines = machineDao.checkMachineNoExist(mons, accountId);
        List<String> machineNOs = machines.stream().map(Machine::getMachineNO).collect(Collectors.toList());
        List<String> noInMachineNos = mons.stream().filter(mon -> !machineNOs.contains(mon)).collect(Collectors.toList());
        return noInMachineNos;
    }

    //使用超级密钥
    private Map<String, String> OTAinitHead(Integer accountId) {
        if (accountId == null) {
            throw new BaseException("请传入运营区域id");
        }
        Integer brandId = accountDao.getBrandIdByAccountIdV2(accountId);
        if (brandId == null) {
            throw new BaseException("账号组织架构不存在");
        }
        Map<String, String> head = new HashMap<>();
        long ts = System.currentTimeMillis();
        log.info("superAppkey:"+superAppkey);
        log.info("superAppSecret:"+superAppSecret);
        String appkey = superAppkey;
        String appSecret = superAppSecret;
        head.put("appkey", appkey);
        head.put("sign", Md5Utils.hash(String.format("%s.%d.%s.%d.%s", appkey, ts, appSecret, ts, appkey)));
        head.put("ts", String.valueOf(ts));
        return head;
    }



    private Map<String, Object> send(String url, Object data, Integer httpType, Integer accountId) {
        /*1为post请求*/
        Map<String, Object> obj = new HashMap<>();
        String result = null;

        Map<String, String> head = OTAinitHead(accountId);
        if (0 == httpType) {
            result = HttpRequestUtils.doPost(url, (Task) data, head);
            if (result == null){
                throw new BaseException("请求ota任务升级失败");
            }
            if (StringUtils.isNotBlank(result) ) {
                if ("500".equals(JSONObject.parseObject(result).get("code").toString())) {
                    throw new BaseException(Optional.ofNullable(JSONObject.parseObject(result).get("msg")).map(Object::toString).orElse("创建任务失败"));
                }
                if ("40001".equals(JSONObject.parseObject(result).get("code").toString())){
                    throw new BaseException("当前id不在范围");
                }
            }
        }
        if (1 == httpType) {
            result = HttpRequestUtils.doPost(url, StringUtils.isNull(data) ? null : JSON.toJSONString(data), head);
        }
        if (2 == httpType) {
            result = HttpRequestUtils.doGet(url, (List<NameValuePair>) data, head);
        }
        log.info("=============" + result + "==============");
        if (StringUtils.isNotNull(result) && result != "") {
            JSONObject jsonObject = JSONObject.parseObject(result);
            if (StringUtils.isNotNull(jsonObject) && 200 == (int) jsonObject.get("code") && jsonObject.get("data") != null) {
                obj.put("data", StringUtils.isNull(jsonObject.get("data")) ? new Object() : jsonObject.get("data"));
            } else if (StringUtils.isNotNull(jsonObject) && 200 == (int) jsonObject.get("code") && jsonObject.get("rows") != null) {
                obj.put("data", StringUtils.isNull(jsonObject.get("rows")) ? new Object() : jsonObject.get("rows"));
                obj.put("total", StringUtils.isNull(jsonObject.get("total")) ? new Object() : jsonObject.get("total"));
            }
            obj.put("msg", jsonObject.get("msg"));
        }
        return obj;
    }


    //ota升级的请求头是超级密钥
    private Map<String, Object> OTAsend(String url, Object data, Integer httpType, Integer accountId) {
        /*1为post请求*/
        Map<String, Object> obj = new HashMap<>();
        String result = null;

        Map<String, String> head = OTAinitHead(accountId);
        if (0 == httpType) {
            result = HttpRequestUtils.doPost(url, (Task) data, head);
            if (result == null){
                throw new BaseException("请求ota任务升级失败");
            }
            if (StringUtils.isNotBlank(result) ) {
                if ("500".equals(JSONObject.parseObject(result).get("code").toString())) {
                    throw new BaseException(Optional.ofNullable(JSONObject.parseObject(result).get("msg")).map(Object::toString).orElse("创建任务失败"));
                }
            }
        }
        if (1 == httpType) {
            result = HttpRequestUtils.doPost(url, StringUtils.isNull(data) ? null : JSON.toJSONString(data), head);
        }
        if (2 == httpType) {
            result = HttpRequestUtils.doGet(url, (List<NameValuePair>) data, head);
        }
        log.info("=============" + result + "==============");
        if (StringUtils.isNotNull(result) && result != "") {
            JSONObject jsonObject = JSONObject.parseObject(result);
            if (StringUtils.isNotNull(jsonObject) && 200 == (int) jsonObject.get("code") && jsonObject.get("data") != null) {
                obj.put("data", StringUtils.isNull(jsonObject.get("data")) ? new Object() : jsonObject.get("data"));
            } else if (StringUtils.isNotNull(jsonObject) && 200 == (int) jsonObject.get("code") && jsonObject.get("rows") != null) {
                obj.put("data", StringUtils.isNull(jsonObject.get("rows")) ? new Object() : jsonObject.get("rows"));
                obj.put("total", StringUtils.isNull(jsonObject.get("total")) ? new Object() : jsonObject.get("total"));
            }
            obj.put("msg", jsonObject.get("msg"));
        }
        return obj;
    }


}
